package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.feigns.admin.AdminFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.vos.HotArticleVo;
import com.heima.model.common.constants.ArticleConstants;
import com.heima.model.common.dtos.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
@Slf4j
public class HotArticleServiceImpl implements HotArticleService {

    @Autowired
    ApArticleMapper apArticleMapper;


    /**
     * 计算热文章(定时任务 xxl-job)
     */
    @Override
    public void computeHotArticle() {

        //1 查询前5天的文章列表
        String dateParam = DateTime.now().minusDays(5).toString("yyyy-MM-dd 00:00:00");
        List<ApArticle> apArticleList = apArticleMapper.selectList(Wrappers.<ApArticle>lambdaQuery().ge(ApArticle::getPublishTime, dateParam));

        //2 计算文章的分值
        List<HotArticleVo> hotArticleVos = computeArticleScore(apArticleList);
        if (hotArticleVos==null) return;

        //3 缓存各个频道下的热点文章（30条， 默认的推荐）
        cacheTagToRedis(hotArticleVos);
    }

    @Autowired
    AdminFeign adminFeign;

    /**
     * 处理文章热点数据  并且缓存到redis
     * @param hotArticleVos
     */
    private void cacheTagToRedis(List<HotArticleVo> hotArticleVos) {

        //1 查询所有的频道列表
        ResponseResult result = adminFeign.findAll();
        if (result.getCode() == 0) {

            List<AdChannel> adChannels = JSON.parseArray(JSON.toJSONString(result.getData()), AdChannel.class);

            // 遍历频道列表
            adChannels.forEach( adChannel -> {

                // 查询各个频道下所有的文章
                List<HotArticleVo> articleVos = hotArticleVos.stream().filter( hotArticleVo1 ->
                        adChannel.getId().equals( hotArticleVo1.getChannelId()) )
                        .collect(Collectors.toList());

                    //2 按照分数排序 30
                    //3 缓存 各个频道下的文章
                sortAndCache(articleVos, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + adChannel.getId());

            } );


            //4 缓存 首页推荐文章
            sortAndCache(hotArticleVos, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG);

        }

    }

    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 给文章排序并且缓存到 Redis
     * @param articleVos
     * @param key
     */
    private void sortAndCache(List<HotArticleVo> articleVos, String key) {

        // 1 排序(分值)
        List<HotArticleVo> hotArticleVos = articleVos.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed()).collect(Collectors.toList());

        //2 取前30条
        if (hotArticleVos.size() > 30) {
            hotArticleVos = hotArticleVos.subList(0, 30);
        }
        //3 缓存
        redisTemplate.opsForValue().set(key, JSON.toJSONString(hotArticleVos));
        log.info("--------------redisTemplate sortAndCache success------------");
    }

    /**
     * 计算文章的分值
     * @param apArticleList
     * @return
     */
    private List<HotArticleVo> computeArticleScore(List<ApArticle> apArticleList) {

        List<HotArticleVo> articleVos = new ArrayList<>();

        if (apArticleList != null && apArticleList.size() > 0) {

            for (ApArticle apArticle : apArticleList) {

                HotArticleVo hotArticleVo = new HotArticleVo();
                BeanUtils.copyProperties(apArticle, hotArticleVo);

                // 计算分值
                Integer score = computeScore(hotArticleVo);
                hotArticleVo.setScore(score);

                // 添加集合
                articleVos.add(hotArticleVo);
            }

            return articleVos;
        }


        return null;
    }

    /**
     * 计算分值：阅读：1，点赞：3，评论：5，收藏：8
     * @param hotArticleVo
     * @return
     */
    private Integer computeScore(HotArticleVo hotArticleVo) {

        int score = 0;

        // 阅读 1
        if (hotArticleVo.getViews() != null) {
            score += hotArticleVo.getViews() * ArticleConstants.HOT_ARTICLE_VIEW_WEIGHT;
        }
        // 点赞 3
        if (hotArticleVo.getLikes() != null) {
            score += hotArticleVo.getLikes() * ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        // 评论 5
        if (hotArticleVo.getComment() != null) {
            score += hotArticleVo.getComment() * ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        // 收藏 8
        if (hotArticleVo.getCollection() != null) {
            score += hotArticleVo.getCollection() * ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }

        return score;

    }
}
